package jmotioncapture.testing.framework.frameCalculation;

import java.awt.Color;
import java.awt.Font;
import java.awt.SystemColor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.ListSelectionModel;
import javax.swing.WindowConstants;
import javax.swing.border.TitledBorder;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;

import jmotioncapture.calculation.GeomCalculation;
import jmotioncapture.calculation.ShapeRecognizer;
import jmotioncapture.camera.Frame;
import jmotioncapture.camera.FrameSet;
import jmotioncapture.camera.Screen;
import jmotioncapture.geometry2D.Line;
import jmotioncapture.geometry2D.Point;
import jmotioncapture.geometry2D.PointComparable;
import jmotioncapture.testing.framework.util.TwoFilterTable;

public class FrameCalculationTestingPanel {

	private JTextArea textArea;

	private JLabel areaLabel;

	/**
	 * GUI Variable - Title
	 */
	private JLabel allPointsLabel;

	/**
	 * GUI Variable - Showing all the point in that frame
	 */
	private JList allPointsList;

	/**
	 * GUI Variable - Showing the list of points after running giftWrappingBound
	 */
	private JList giftWrappingBoundList;

	/**
	 * GUI Variable - Title
	 */
	private JLabel giftwrappingboundAlgorithmLabel;

	/**
	 * GUI Variable - Showing the intersection point of 2 lines
	 */
	private JLabel intersectionPointLabel;

	/**
	 * GUI Variable - Showing the angle between 2 lines
	 */
	private JLabel angleBetween2LinesLabel;

	/**
	 * GUI Variable - Scroll Pane of statistics table
	 */
	private JScrollPane statisticsScrollPane;

	/**
	 * GUI Variable - Showing the statistics of all frames
	 */
	private JTable statisticsTable;

	/**
	 * GUI Variable - Clicked if need to show point in screen
	 */
	private JCheckBox showPointCheckBox;

	/**
	 * GUI Variable - Clicked if need to show link in screen
	 */
	private JCheckBox showLinkCheckBox;

	/**
	 * GUI Variable - Clicked if need to show label in screen
	 */
	private JCheckBox showLabelCheckBox;

	/**
	 * GUI Variable - Showing all the frame
	 */
	private JList framesList;

	/**
	 * GUI Variable - Showing the actual points detected
	 */
	private JPanel drawingPanel;

	/**
	 * GUI Variable - Main frame
	 */
	public JFrame frame;

	/**
	 * GUI variable - Constructing the statistics table
	 */
	private TwoFilterTable tft;

	/**
	 * GUI Variable - Listing all the frames
	 */
	private DefaultListModel frameListModel = new DefaultListModel();

	/**
	 * GUI Variable - Listing all the points at specific frame
	 */
	private DefaultListModel allPointsListModel = new DefaultListModel();

	/**
	 * GUI Variable - Listing all the point which bound the max area and sorted
	 * clockwise
	 */
	private DefaultListModel giftWrappingBoundListModel = new DefaultListModel();

	private FrameSet frames;

	private Vector<Point> giftWrappingBoundPoints;

	private Screen screen = new Screen();

	// *************************
	// * Create the application
	// *************************

	/**
	 * Refresh all the display details after selecting a frame
	 */
	private void refreshAfterSelectFrame() {

		Frame selectFrame = frames.frameAt(framesList.getSelectedIndex());

		refreshGiftWrappingBoundList(selectFrame);
		refreshPointList(selectFrame);
		refreshDrawingPanel(selectFrame);
		refreshLineStatisticsTable(selectFrame);
		refreshFrameMaxArea(selectFrame);
		refreshScreen();

		// Must Run at last
		refreshTextArea();
	}

	/**
	 * Adding the frames details to <code>frameListModel</code>
	 */
	public FrameCalculationTestingPanel(FrameSet frames) {
		this.frames = frames;
		initialize();

		for (int i = 0; i < frames.size(); i++)
			frameListModel.addElement("Frame " + (i + 1));
	}

	/**
	 * Refresh the drawing panel
	 * 
	 * @param selectFrame
	 *            <code>Selected Frame</code>
	 */
	private void refreshDrawingPanel(Frame selectFrame) {

		boolean showLink = this.showLinkCheckBox.isSelected();
		boolean showPoint = this.showPointCheckBox.isSelected();
		boolean showLabel = this.showLabelCheckBox.isSelected();
		int[] selectedLines = this.statisticsTable.getSelectedRows();

		DrawPanel_FrameCalculationTesting drawing = new DrawPanel_FrameCalculationTesting(
				selectFrame, frames, showPoint, showLabel, showLink,
				selectedLines);

		this.drawingPanel = drawing;
		this.drawingPanel.setLayout(null);
		this.drawingPanel.setBorder(new TitledBorder(null, "",
				TitledBorder.DEFAULT_JUSTIFICATION,
				TitledBorder.DEFAULT_POSITION, null, null));
		this.drawingPanel.setBackground(Color.WHITE);
		drawingPanel.setBounds(222, 39, 472, 491);

		this.frame.getContentPane().add(drawingPanel);
		this.drawingPanel.repaint();

	}

	/**
	 * Refresh the Points List
	 * 
	 * @param selectFrame
	 *            <code>Selected Frame</code>
	 */
	private void refreshPointList(Frame selectFrame) {

		allPointsListModel.removeAllElements();

		Vector<Point> pts = selectFrame.getPoints();
		for (int i = 0; i < pts.size(); i++)
			this.allPointsListModel.addElement("P" + pts.elementAt(i).getID()
					+ pts.elementAt(i).toString());

	}

	/**
	 * Refresh the GiftWrappingBound List
	 * 
	 * @param selectFrame
	 *            <code>Selected Frame</code>
	 */
	private void refreshGiftWrappingBoundList(Frame selectFrame) {

		giftWrappingBoundListModel.removeAllElements();

		giftWrappingBoundPoints = selectFrame.getMaximunAreaBoundPoints();
		for (int i = 0; i < giftWrappingBoundPoints.size(); i++)
			this.giftWrappingBoundListModel.addElement("P"
					+ giftWrappingBoundPoints.elementAt(i).getID()
					+ giftWrappingBoundPoints.elementAt(i).toString());
	}

	/**
	 * Refresh the line statistics table
	 * 
	 * @param selectFrame
	 *            <code>Selected Frame</code>
	 */
	private void refreshLineStatisticsTable(Frame selectFrame) {

		Vector<Line> lines = selectFrame.getLines();

		// Pt1, Pt2, Slope, PolarAng, Distance
		String[] columnNames = new String[] { "L#", "StartPt", "EndPt",
				"Slope", "PoAng", "Dist" };
		int[] columnWidth = new int[] { 5, 20, 20, 10, 10, 10 };
		int[] columnAlignment = new int[] { JLabel.CENTER, JLabel.CENTER,
				JLabel.CENTER, JLabel.CENTER, JLabel.CENTER, JLabel.CENTER };
		Object[][] data = new Object[lines.size()][columnNames.length];

		for (int i = 0; i < data.length; i++) {

			data[i][0] = "L" + (i + 1);
			data[i][1] = lines.elementAt(i).getStartPoint().toString();
			data[i][2] = lines.elementAt(i).getEndPoint().toString();
			data[i][3] = (double) lines.elementAt(i).getSlope();
			data[i][4] = (double) lines.elementAt(i).getPolarAngle();
			data[i][5] = (double) lines.elementAt(i).getDistance();
		}

		tft = new TwoFilterTable(columnNames, data, columnWidth,
				columnAlignment, 0, 1);

		statisticsTable = tft.getTable();
		statisticsTable
				.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
		statisticsScrollPane.setViewportView(statisticsTable);
		statisticsScrollPane.paintAll(statisticsScrollPane.getGraphics());
	}

	/**
	 * Refresh the area with the selected frame
	 * 
	 * @param selectFrame
	 */
	private void refreshFrameMaxArea(Frame selectFrame) {
		this.areaLabel.setText("Area: " + selectFrame.maxBoundedArea());
	}

	/**
	 * Refresh the Screen object
	 * 
	 */
	private void refreshScreen() {

		int index = framesList.getSelectedIndex();
		FrameSet analysis_FrameSet = frames.framesBetween(0, index, 0);

		screen.init(analysis_FrameSet, frames.frameAt(index));
	}

	/**
	 * Refresh the calculation
	 * 
	 * @param selectFrame
	 */
	private void refreshTextArea() {

		textArea.setText("");
		addLineToTextArea("ShapeRecognizer:");
		addLineToTextArea("ShapeRecognizer.isRectangle(): "
				+ ShapeRecognizer.isRectangle(giftWrappingBoundPoints));
		addLineToTextArea("ShapeRecognizer.isSquare(): "
				+ ShapeRecognizer.isSquare(giftWrappingBoundPoints));
		addLineToTextArea("================================");
		addLineToTextArea("Screen: " + screen.getStatus());

		if (screen.getStatus())
			addLineToTextArea(screen.toString());

	}

	/**
	 * Add a string to the textarea
	 * 
	 * @param line
	 */
	private void addLineToTextArea(String line) {
		textArea.append(line + "\n");
	}

	/**
	 * Event handler for calButton
	 */
	private void calButton_Click() {
		int[] rows = this.statisticsTable.getSelectedRows();

		if (rows.length == 2) {
			String line1pt1 = statisticsTable.getValueAt(rows[0], 1).toString();
			String line1pt2 = statisticsTable.getValueAt(rows[0], 2).toString();
			String line2pt1 = statisticsTable.getValueAt(rows[1], 1).toString();
			String line2pt2 = statisticsTable.getValueAt(rows[1], 2).toString();

			line1pt1 = line1pt1.substring(1, line1pt1.length() - 1);
			line1pt2 = line1pt2.substring(1, line1pt2.length() - 1);
			line2pt1 = line2pt1.substring(1, line2pt1.length() - 1);
			line2pt2 = line2pt2.substring(1, line2pt2.length() - 1);

			String[] temp = line1pt1.split(",");
			Point pt1 = new Point(Short.parseShort(temp[0]), Short
					.parseShort(temp[1]));

			temp = line1pt2.split(",");
			Point pt2 = new Point(Short.parseShort(temp[0]), Short
					.parseShort(temp[1]));

			temp = line2pt1.split(",");
			Point pt3 = new Point(Short.parseShort(temp[0]), Short
					.parseShort(temp[1]));

			temp = line2pt2.split(",");
			Point pt4 = new Point(Short.parseShort(temp[0]), Short
					.parseShort(temp[1]));

			Line line1 = new Line(pt1, pt2);
			Line line2 = new Line(pt3, pt4);

			angleBetween2LinesLabel.setText("Angle between 2 lines:"
					+ GeomCalculation.getAngleBetweenTwoLines(line1, line2));

			intersectionPointLabel
					.setText("Intersection Point: "
							+ GeomCalculation.intersectionPointOfTwoLines(
									line1, line2));
		}
	}

	/**
	 * Event handler for giftWrappingBoundButton
	 */
	private void giftWrappingBoundButton_Click() {

		if (giftWrappingBoundPoints == null)
			return;

		Frame selectFrame = new Frame(this.giftWrappingBoundPoints, System
				.currentTimeMillis());

		DrawPanel_FrameCalculationTesting drawing = new DrawPanel_FrameCalculationTesting(
				selectFrame, frames, true, true, true, null);

		this.drawingPanel = drawing;
		this.drawingPanel.setLayout(null);
		this.drawingPanel.setBorder(new TitledBorder(null, "",
				TitledBorder.DEFAULT_JUSTIFICATION,
				TitledBorder.DEFAULT_POSITION, null, null));
		this.drawingPanel.setBackground(Color.WHITE);
		drawingPanel.setBounds(222, 39, 472, 491);

		this.frame.getContentPane().add(drawingPanel);
		this.drawingPanel.repaint();
	}

	/**
	 * Event handler for sortXButton
	 */
	private void sortXButton_Click() {

		this.allPointsListModel.removeAllElements();

		PointComparable[] ptcs = frames.frameAt(
				this.framesList.getSelectedIndex()).sortPointsByX();

		for (int i = 0; i < ptcs.length; i++)
			this.allPointsListModel.addElement("P" + ptcs[i].getID()
					+ ptcs[i].toString());

	}

	/**
	 * Event handler for sortYButton
	 */
	private void sortYButton_Click() {

		this.allPointsListModel.removeAllElements();

		PointComparable[] ptcs = frames.frameAt(
				this.framesList.getSelectedIndex()).sortPointsByY();

		for (int i = 0; i < ptcs.length; i++)
			this.allPointsListModel.addElement("P" + ptcs[i].getID()
					+ ptcs[i].toString());

	}

	/**
	 * Initialize the contents of the frame
	 */
	private void initialize() {
		frame = new JFrame();
		frame.getContentPane().setLayout(null);
		frame.setTitle("Line Algorithm");
		frame.setResizable(false);
		frame.setBounds(100, 100, 1119, 643);
		frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

		drawingPanel = new JPanel();
		drawingPanel.setBorder(new TitledBorder(null, "",
				TitledBorder.DEFAULT_JUSTIFICATION,
				TitledBorder.DEFAULT_POSITION, null, null));
		drawingPanel.setLayout(null);
		drawingPanel.setBackground(Color.WHITE);
		drawingPanel.setBounds(222, 39, 472, 491);
		frame.getContentPane().add(drawingPanel);

		final JScrollPane framesListScrollPane = new JScrollPane();
		framesListScrollPane.setBounds(10, 39, 100, 491);
		frame.getContentPane().add(framesListScrollPane);

		framesList = new JList(frameListModel);
		framesList.addKeyListener(new KeyAdapter() {
			public void keyPressed(final KeyEvent arg0) {
				refreshAfterSelectFrame();
			}
		});
		framesList.addMouseListener(new MouseAdapter() {
			public void mouseClicked(final MouseEvent arg0) {
				refreshAfterSelectFrame();
			}
		});
		framesListScrollPane.setViewportView(framesList);

		showLinkCheckBox = new JCheckBox();
		showLinkCheckBox.setSelected(true);
		showLinkCheckBox.setText("Show Link");
		showLinkCheckBox.setBounds(311, 536, 73, 23);
		frame.getContentPane().add(showLinkCheckBox);

		showPointCheckBox = new JCheckBox();
		showPointCheckBox.setSelected(true);
		showPointCheckBox.setText("Show Point");
		showPointCheckBox.setBounds(390, 536, 79, 23);
		frame.getContentPane().add(showPointCheckBox);

		showLabelCheckBox = new JCheckBox();
		showLabelCheckBox.setSelected(true);
		showLabelCheckBox.setText("Show Label");
		showLabelCheckBox.setBounds(475, 536, 79, 23);
		frame.getContentPane().add(showLabelCheckBox);

		final JButton refreshDisplayButton = new JButton();
		refreshDisplayButton.addActionListener(new ActionListener() {
			public void actionPerformed(final ActionEvent arg0) {
				refreshAfterSelectFrame();
			}
		});
		refreshDisplayButton.setText("Refresh Display");
		refreshDisplayButton.setBounds(560, 536, 134, 23);
		frame.getContentPane().add(refreshDisplayButton);

		statisticsScrollPane = new JScrollPane();
		statisticsScrollPane.setBounds(710, 39, 393, 130);
		frame.getContentPane().add(statisticsScrollPane);

		statisticsTable = new JTable();
		statisticsScrollPane.setViewportView(statisticsTable);

		final JPanel twoLinesCalculationPanel = new JPanel();
		twoLinesCalculationPanel
				.setBackground(SystemColor.inactiveCaptionBorder);
		twoLinesCalculationPanel.setLayout(null);
		twoLinesCalculationPanel.setBounds(710, 188, 393, 76);
		frame.getContentPane().add(twoLinesCalculationPanel);

		final JLabel calFor2Label = new JLabel();
		calFor2Label.setFont(new Font("", Font.BOLD, 12));
		calFor2Label.setText("Calculation for 2 lines:");
		calFor2Label.setBounds(10, 10, 139, 14);
		twoLinesCalculationPanel.add(calFor2Label);

		angleBetween2LinesLabel = new JLabel();
		angleBetween2LinesLabel.setBounds(10, 30, 373, 14);
		twoLinesCalculationPanel.add(angleBetween2LinesLabel);
		angleBetween2LinesLabel.setText("Angle between 2 lines:");

		intersectionPointLabel = new JLabel();
		intersectionPointLabel.setBounds(10, 50, 373, 14);
		twoLinesCalculationPanel.add(intersectionPointLabel);
		intersectionPointLabel.setText("Intersection Point:");

		final JButton calButton = new JButton();
		calButton.addActionListener(new ActionListener() {
			public void actionPerformed(final ActionEvent arg0) {
				calButton_Click();
			}
		});
		calButton.setText("Cal");
		calButton.setBounds(290, 6, 93, 23);
		twoLinesCalculationPanel.add(calButton);

		giftwrappingboundAlgorithmLabel = new JLabel();

		giftwrappingboundAlgorithmLabel.setText("giftWrappingBound:");
		giftwrappingboundAlgorithmLabel.setBounds(116, 19, 100, 14);
		frame.getContentPane().add(giftwrappingboundAlgorithmLabel);

		final JScrollPane giftWrappingBoundListScrollPane = new JScrollPane();
		giftWrappingBoundListScrollPane.setBounds(116, 39, 100, 225);
		frame.getContentPane().add(giftWrappingBoundListScrollPane);

		giftWrappingBoundList = new JList(giftWrappingBoundListModel);
		giftWrappingBoundListScrollPane.setViewportView(giftWrappingBoundList);

		final JScrollPane allPointsScrollPane = new JScrollPane();
		allPointsScrollPane.setBounds(116, 318, 100, 212);
		frame.getContentPane().add(allPointsScrollPane);

		allPointsList = new JList(allPointsListModel);
		allPointsScrollPane.setViewportView(allPointsList);

		allPointsLabel = new JLabel();
		allPointsLabel.setText("All Points:");
		allPointsLabel.setBounds(116, 298, 100, 14);
		frame.getContentPane().add(allPointsLabel);

		final JButton giftWrappingBoundButton = new JButton();
		giftWrappingBoundButton.addActionListener(new ActionListener() {
			public void actionPerformed(final ActionEvent arg0) {
				giftWrappingBoundButton_Click();
			}
		});
		giftWrappingBoundButton.setText("Show");
		giftWrappingBoundButton.setBounds(116, 269, 100, 23);
		frame.getContentPane().add(giftWrappingBoundButton);

		final JButton sortXButton = new JButton();
		sortXButton.addActionListener(new ActionListener() {
			public void actionPerformed(final ActionEvent arg0) {
				sortXButton_Click();
			}
		});
		sortXButton.setText("Sorting by X");
		sortXButton.setBounds(116, 536, 100, 23);
		frame.getContentPane().add(sortXButton);

		final JButton sortYButton = new JButton();
		sortYButton.addActionListener(new ActionListener() {
			public void actionPerformed(final ActionEvent arg0) {
				sortYButton_Click();
			}
		});
		sortYButton.setText("Sorting by Y");
		sortYButton.setBounds(116, 565, 100, 23);
		frame.getContentPane().add(sortYButton);

		areaLabel = new JLabel();
		areaLabel.setText("Area:");
		areaLabel.setBounds(222, 19, 472, 14);
		frame.getContentPane().add(areaLabel);

		final JScrollPane textAreaScrollPane = new JScrollPane();
		textAreaScrollPane.setBounds(710, 270, 393, 289);
		frame.getContentPane().add(textAreaScrollPane);

		textArea = new JTextArea();
		textAreaScrollPane.setViewportView(textArea);

		final JLabel descriptionLabel = new JLabel();
		descriptionLabel.setText("* Bigger point is static point");
		descriptionLabel.setBounds(559, 565, 135, 15);
		frame.getContentPane().add(descriptionLabel);
	}
}
